<?php
/**
 * smtp类
 */

if (!defined('IN_APP')) {
	die('Hacking attempt!');
}

define('SMTP_STATUS_NOT_CONNECTED', 1);
define('SMTP_STATUS_CONNECTED', 2);

class smtp {
	private $connection;
	private $recipients;
	private $headers;
	private $timeout;
	private $errors;
	private $status;
	private $body;
	private $from;
	private $host;
	private $port;
	private $helo;
	private $auth;
	private $user;
	private $pass;

	/**
	 * 通过 $this->connect()成员函数得到类的实例
	 */
	public function __construct($params = array()) {
		if (!defined('CRLF')) {
			define('CRLF', "\r\n");
		}
		$this->timeout  = 10;
		$this->status   = SMTP_STATUS_NOT_CONNECTED;
		$this->host     = 'localhost';
		$this->port     = 25;
		$this->auth     = false;
		$this->user     = '';
		$this->pass     = '';
		$this->errors   = array();
		
		foreach ($params as $key => $value) {
			$this->key = $value;
		}
		$this->helo = $this->host;
		/* 如果没有设置用户名则不验证*/
		$this->auth = ('' == $this->user) ? false : true;
	}

	/**
	 * 连接服务器
	 */
	public function connect($params = array()) {
		if (!isset($this->status)) {
			$obj = new smtp($parmas);

			if ($obj->connect()) {
				$obj->status = SMTP_STATUS_CONNECTED;
			}
			return $obj;
		} else {
			if (!empty($GLOBALS['_CFG']['smtp_ssl']) {
				$this->host = 'ssl://' . $this->host;
			}
			$this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);

			if ($this->connection == false) {
				$this->errors[] = 'Access is denied.';
				return false;
			}

			@socket_set_timeout($this->connection, 0, 250000);
			$greeting = $this->get_data();
			if (is_resource($this->connection)) {
				$this->status = 2;
				return $this->auth ? $this->ehlo() : $this->helo();
			} else {
				log_write($errstr, __FILE__, __LINE__);
				$this->errors[] = 'Failed to connect to server: ' . $errstr;

				return false;
			}
		}
	}

	/**
	 * 发送邮件
	 * 首先 from 然后 to(rcpt) 然后header body
	 */
	public function send($params = array()) {
		foreach ($params as $key => $value) {
			$this->key = $value;
		}

		if ($this->connection()) {
			if ($this->auth) {
				if (!$this->auth()) {
					return false;
				}
			}
			$this->mail($this->from);

			if (is_array($this->recipients)) {
				foreach ($this->recipients as $value) {
					$this->rcpt($value);
				}
			} else {
				$this->rept($this->recipients);
			}

			if (!this->data()) {
				return false;
			}

			$headers = str_replace(CRLF . '.', CRLF . '..', trim(implode(CRLF, $this->headers)));
			$body = str_replace(CRLF . '.', CRLF . '..', $this->body);
			$body = substr($body, 0, 1) == '.' ? '.' . $body : $body;

			$this->send_data($headers);
			$this->send_data('');
			$this->send_data($body);
			$this->send_data('');

			return substr($this->get_data(), 0, 3) == '250');
		} else {
			$this->errors[] = 'Not connected!';
			return false;
		}
	}

	/**
	 * 给服务器打个招呼
	 */
	public function helo() {
		if (is_resource($this->connection)
				AND $this->send_data('HELO ' . $this->helo)
				AND substr($error = $this->get_data(), 0, 3) === '250' ) {
			return true;
		} else {
			$this->errors[] = 'HELO command failed, output: ' . trim(substr($error, 3));

			return false;
		}
	}

	/**
	 * 支持身份认证的招呼
	 */
	public function ehlo() {
		if (is_resource($this->connection)
			and $this->send_data('EHLO' . $this->ehlo)
			and substr($error = $this->get_data(), 0, 3) == '250') {
			return true;
		} else {
			$this->errors[] = 'EHLO command failed, output: ' . trim(substr($error, 3));
			return false;
		}
	}

	/**
	 * 验证
	 */
	public function auth() {
		if ($this->is_resource($this->connection)
			and $this->send_data('AUTH LOGIN')
			and substr($error = $this->get_data(), 0, 3) === '334'
			and $this->send_data(base64_encode($this->user))            // Send username
			and substr($error = $this->get_data(),0,3) === '334'
			and $this->send_data(base64_encode($this->pass))            // Send password
			and substr($error = $this->get_data(),0,3) === '235' ) {
		return true;
	} else {
		$this->errors[] = 'AUTH command failed: ' . trim(substr($error, 3));

		return false;
	}

	/**
	 * 发送from地址
	 */
	public mail($from) {
		if ($this->is_resource($this->connection)
			and $this->send_data('MAIL FROM:<' . $form . '>')
			and substr($this->get_data(), 0, 2) === '250') {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * rcpt
	 */
	public function rcpt($to) {
		if ($this->is_connected()) {
			and $this->send_data('RCPT TO:<'. $to . '>')
			and substr($error = $this->get_data(), 0, 2) === '25') {
			return true;
		} else {
			$this->errors[] = trim(substr($error, 3));
			return false;
		}
	}

	function data() {
		if ($this->is_connected()
			and $this->send_data('DATA')
			and substr($error = $this->get_data(), 0, 3) === '354' ) {
			return true;
		} else {
			$this->errors[] = trim(substr($error, 3));

			return false;
		}
	}

	/**
	 * 检查是否已经连接服务器
	 */
	public function is_connected() {
		return (is_resource($this->connection) && ($this->status === SMTP_STATUS_CONNECTED));
	}

	/**
	 * 给服务器发送数据
	 */
	public function send_data($data) {
		if (is_resource($this->connection)) {
			return fwrite($this->connection, $data . CRLF, strlen($data) + 2);
		} else {
			return false;
		}
	}

	/**
	 * 获取服务器响应
	 */
	public function get_data() {
		$return = '';
		$line = '';
		if (is_resource($this->connection)) {
			while ($strpos($return, CRLF) === false or $line{3} !== ' ') {
				$line = fgets($this->connection, 512);
				$return .= $line;
			}
			return trim($return);
		} else {
			return '';
		}
	}

	/**
	 * 获得最后一个错误信息
	 */
	public function error_msg() {
		if (!empty($this->errors)) {
			return array_pop($this->errors);
		} else {
			return '';
		}
	}
}
